//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================

#include <elasys_server.h>
#include <winhack.h>
#include <aura.h>

static IMutex *g_pEnvMutex;

class CEnvironMutex : public IMutex
{
public:
    CARAPI_(UInt32)AddRef();
    CARAPI_(UInt32)Release();
    CARAPI_(PInterface) Probe(REIID);
    CARAPI Aggregate(AggregateType, PInterface){return 0;}
    CARAPI GetDomain(PInterface*){return 0;}
    ECode Initialize();
    CARAPI Lock(WaitResult *pResult);
    CARAPI Unlock();
    CARAPI TryLock(INT msTimeout, WaitResult *pResult){return 0;}

public:
    Interlocked m_cRef;
    HANDLE    m_hMutex;
};

UInt32 CEnvironMutex::AddRef()
{
    LONG nRef = m_cRef.Increment();
    return (ULONG)nRef;
}

UInt32 CEnvironMutex::Release()
{
    LONG nRef = m_cRef.Decrement();
    if (nRef == 0) {
        delete this;
//        DecrementDllLockCount(); // one obj's been removed
    }
    return (ULONG)nRef;
}

PInterface CEnvironMutex::Probe(REIID riid)
{
    if (riid == EIID_IInterface) {
        return (IInterface *)this;
    }
    else if (riid == EIID_IMutex) {
        return (IMutex *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CMutex;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface) &EIID_IMutex;
    }

    return NULL;
}

ECode CEnvironMutex::Initialize()
{
    m_hMutex = CreateMutexW(NULL, FALSE, NULL);
    return m_hMutex?NOERROR:E_INVALID_OPERATION;
}

ECode CEnvironMutex::Lock(
    /* [out] */ WaitResult * pResult)
{
    ECode ec = NOERROR;
    DWORD res = WaitForSingleObjectEx(m_hMutex, (DWORD)INFINITE, TRUE);
    switch (res) {
        case WAIT_OBJECT_0:
            *pResult = WaitResult_OK;
            break;
        case WAIT_IO_COMPLETION:
            *pResult = WaitResult_Interrupted;
            break;
        default:
            ec = E_INVALID_OPERATION;
            break;
    }
    return ec;
}

ECode CEnvironMutex::Unlock()
{
    Boolean bSuccess = ReleaseMutex(m_hMutex);
    return bSuccess?NOERROR:E_INVALID_OPERATION;
}

extern "C" IMutex * __cdecl EnvironMutex()
{
    if (NULL == g_pEnvMutex) {
        CEnvironMutex *pcMutex = new CEnvironMutex();
        if (NULL == pcMutex) {
            return NULL;
        }
        if (FAILED(pcMutex->Initialize())) {
            return NULL;
        }
        g_pEnvMutex = (IMutex*)pcMutex;
        assert(g_pEnvMutex);
    }

    return g_pEnvMutex;
}

//extern "C" IMutex * __cdecl EnvironMutex()
//{
//    if (NULL == g_pEnvMutex) {
//        _EzGetEnvironMutex(&g_pEnvMutex);
//        assert(g_pEnvMutex);
//    }
//    return g_pEnvMutex;
//}

